//
//  SerieModificationViewController.swift
//  Automobile
//
//  Created by erkebulan elzhan on 8/12/20.
//  Copyright © 2020 erkebulan elzhan. All rights reserved.
//

import UIKit


final class SerieModificationViewModel {
    var podtypModels: [SerieModificationViewController.PodtypViewModel] = []
}

// MARK: - [Car Select View] mode comments

final class SerieModificationViewController: UIViewController, Alertable {

    struct PodtypViewModel: ModelCellData {
        
        var model: PodtypModel!
        
        var postfix: String?=""
        
        var id: Int {
            return model.id
        }
        
        var name: String {
            return model.name + (postfix ?? "")
        }
        
        var serieName: String = ""
        
        var isSelected: Bool = false
        
        var custom: Any? = nil
        
        init (model: PodtypModel) {
            self.model = model
        }
    }
    
    struct PodtypModel: Decodable {
        var id: Int
        var ext: Int
        var name: String
    }
    
    enum VCType: String {
        case serie = "Серия", modification = "Модификация", color = "Цвет"
    }
    
    // MARK: - Outlets

    lazy private var modelsScroll: ModelsScroll = {
        let modelsScroll = ModelsScroll(models: self.models)
        return modelsScroll
    }()

    lazy private var tableView:UITableView = {
        let table = UITableView()
        table.delegate = self
        table.dataSource = self
        table.register(ModelCell.self, forCellReuseIdentifier: "modelCell")
        table.showsVerticalScrollIndicator = false
        table.backgroundColor = .white
        table.tableFooterView = UIView()
        table.separatorStyle = .none
        return table
    }()

    lazy private var spinner = SpinnerView()

    lazy private var nextBtn: UIButton = {
        let btn = UIButton()
        btn.clipsToBounds = true
        btn.layer.cornerRadius = 15
        btn.setTitle("Далее", for: .normal)
        btn.backgroundColor = .lightBlueColor
        btn.setTitleColor(.greyColor, for: .normal)
        btn.titleLabel!.font = UIFont.systemFont(ofSize: 17, weight: .medium)
        return btn
    }()
    
     private lazy var submitBtn: UIButton = {
        let btn = UIButton()
        btn.clipsToBounds = true
        btn.layer.cornerRadius = 15
        btn.setTitle("Выбрать", for: .normal)
        btn.backgroundColor = .blueColor
        btn.setTitleColor(.white, for: .normal)
        btn.titleLabel!.font = UIFont.systemFont(ofSize: 17, weight: .medium)
        return btn
    }()

    private lazy var emptyView: EmptyView = {
        let emptyView = EmptyView()
        emptyView.frame = CGRect(x: 0, y: 0, width: tableView.frame.width, height: 200)
        return emptyView
    }()


    // MARK: - Props

    public var resultsVC: ResultsVCDelegate!
    public var carData: CarData!
    public var vcType: VCType = .serie
    public var models: [Model]!

    
    private var scrollModels: [Int: [PodtypViewModel]] = [:]
    private var viewModel = SerieModificationViewModel()
    
    private var currentModelIndex: Int = 0
    private var lastSelectedRow: Int?
    
    
    private var isLoading: Bool = false {
        didSet {
            isLoading ? spinner.startAnimating() : spinner.stopAnimating()
        }
    }
    
    private var selectedItemsCount = 0 {
        didSet {
            if !isCarCreate {
                // hide at last VC
                nextBtn.isHidden = (vcType == .modification || selectedItemsCount == 0)
            }
        }
    }
    
    
    private var isCarCreate: Bool {
        return resultsVC is SelectCarViewController
    }
    
    // MARK: - Life-Cycle
    
    override func viewDidLoad() {
        super.viewDidLoad()
        selectedItemsCount = 0
        self.setUpUI()
        self.setUpNavBar()
        
        if isCarCreate {
            self.handleSingleSelection()
        }
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        NotificationCenter.default.addObserver(self, selector: #selector(updateModel(notification:)), name: NSNotification.Name("setModel"), object: nil)
        self.loadData(model: models[currentModelIndex], index: currentModelIndex)
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name("setModel"), object: nil)
    }
    
    
    // MARK: - Methods
    
    // Update table view for serie
    
    private func fillScrollModels () {
        var _series: [PodtypViewModel] = []
        for __model in (models[currentModelIndex].generation ?? []) {
            for serie in __model.series ?? [] {
                let model = PodtypModel(id: serie.id, ext: serie.ext, name: serie.name)
                let serieModel = PodtypViewModel(model: model)
                _series.append(serieModel)
            }
        }

        scrollModels[currentModelIndex] = _series
        if (_series.count == 0) {
            tableView.tableHeaderView = emptyView
        } else {
            tableView.tableHeaderView = nil
        }
        tableView.reloadData()
    }
    
    private func fillModificationScrollModels () {
        var _modifications: [PodtypViewModel] = []
        
        for __model in (models[currentModelIndex].generation ?? []) {
            for serie in __model.series ?? [] {
                for __modification in serie.modifications ?? [] {
                    let model = PodtypModel(id: __modification.id, ext: __modification.ext, name: __modification.name)
                    var modificationModel = PodtypViewModel(model: model)
                    modificationModel.serieName = serie.name
                    _modifications.append(modificationModel)
                }
            }
        }
        
        scrollModels[currentModelIndex] = _modifications
        if (_modifications.count == 0) {
            tableView.tableHeaderView = emptyView
        } else {
            tableView.tableHeaderView = nil
        }
        tableView.reloadData()
    }
    
    
    private func goToRoot () {
        var found = false
        var index = navigationController!.viewControllers.count - 1
        
        while (!found) {
            if (index != 0) {
                if navigationController!.viewControllers[index] is ResultsViewController || navigationController?.viewControllers[index] is FilterViewController {
                    self.navigationController?.popToViewController((navigationController?.viewControllers[index])!, animated: true)
                    found = true
                } else {
                    index -= 1
                }
            } else {
                found = true
            }
        }
    }
}



extension SerieModificationViewController {
    
    @objc private func goBack (sender: UIBarButtonItem) {
        self.navigationController?.popViewController(animated: true)
    }
    
    @objc private func closeVC (sender: UIBarButtonItem) {
        self.navigationController?.dismiss(animated: true, completion: nil)
    }
    
    @objc private func onSubmit (sender: UIButton) {
        resultsVC.goBack(data: CarFilter(marka: carData.marka, models: self.models),
                         type: carData.mode)
        self.goToRoot()
    }
    
    // only from multi select
    
    @objc private func onNext(sender: UIButton) {
        let vc = SerieModificationViewController()
        vc.vcType = .modification
        vc.resultsVC = self.resultsVC
        vc.models = self.models
        vc.carData = self.carData
        self.navigationController?.pushViewController(vc, animated: true)
    }
    
}


// MARK: - UI Table View

extension SerieModificationViewController: UITableViewDelegate, UITableViewDataSource {
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if isCarCreate {
            if vcType == .serie {
                self.selectSingleSerie(at: indexPath)
            } else if vcType == .modification {
                self.selectSingleModification(at: indexPath)
            } else if vcType == .color {
                self.selectColor(at: indexPath)
            }
        } else {
            self.updateCheckBoxes(at: indexPath)
        }
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return scrollModels[currentModelIndex]?.count ?? 0
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "modelCell") as! ModelCell
        var model = scrollModels[currentModelIndex]?[indexPath.row]
        // [Car Select View]
        
        if !isCarCreate {
            let postfix = vcType == .serie ? " (\(models[currentModelIndex].name_ru))" : " (\(model!.serieName))"
            model?.postfix = postfix
        }
        
        cell.model = model
        cell.selectionStyle = .none
        cell.backgroundColor = .white
        
        if isCarCreate {
            cell.handleSingleSelection(markIcon: carData.markaImg)
            if (vcType == .color) {
                if let color = model?.custom as? UIColor {
                    cell.fillImageWithColor(color)
                }
            }
        }
        
        return cell
    }
    
    private func updateCheckBoxes (at indexPath: IndexPath) {
        if scrollModels[currentModelIndex]?[indexPath.row].isSelected ?? false {
            selectedItemsCount -= 1
        } else {
            selectedItemsCount += 1
        }
        
        scrollModels[currentModelIndex]?[indexPath.row].isSelected.toggle()
        
        if isCarCreate && lastSelectedRow != nil {
            scrollModels[currentModelIndex]?[lastSelectedRow!].isSelected = false
            selectedItemsCount -= 1
            tableView.reloadRows(at: [IndexPath(row: lastSelectedRow!, section: 0)], with: .top)
        }
        
        lastSelectedRow = indexPath.row
        tableView.reloadRows(at: [indexPath], with: .top)
    }
    
    private func selectSingleSerie (at indexPath: IndexPath) {
        let vc = SerieModificationViewController()
        vc.vcType = .modification
        vc.resultsVC = self.resultsVC
        
        var updatedModels = self.models
        
        let podtypModel = scrollModels[currentModelIndex]?[indexPath.row].model
        let serie = Serie(id: podtypModel!.id, ext: podtypModel!.ext, name: podtypModel!.name)
        
        updatedModels?[0].generation?[0].series = [serie]
        
        var _carData = self.carData
        vc.models = updatedModels
        _carData?.models = updatedModels
        vc.carData = _carData
        self.navigationController?.pushViewController(vc, animated: true)
    }
    
    private func selectSingleModification (at indexPath: IndexPath) {
        let vc = SerieModificationViewController()
        vc.vcType = .color
        vc.resultsVC = self.resultsVC
        
        var updatedModels = self.models
        let podtypModel = scrollModels[currentModelIndex]?[indexPath.row].model
        let modification = Modification(id: podtypModel!.id, ext: podtypModel!.ext, name: podtypModel!.name)
        updatedModels?[0].generation?[0].series?[0].modifications = [modification]
        
        var _carData = self.carData
        vc.models = updatedModels
        _carData?.models = updatedModels
        vc.carData = _carData
        self.navigationController?.pushViewController(vc, animated: true)
    }
    
    // Go to Probeg
    
    private func selectColor (at indexPath: IndexPath) {
        if let podtypModel = scrollModels[currentModelIndex]?[indexPath.row].model {
            let color = CarColor(id: podtypModel.id, name: podtypModel.name, ext: podtypModel.ext)
            
            let probegVC = ProbegViewController()
            probegVC.carFilter = CarFilter(marka: carData.marka, models: carData.models!, color: color)
            probegVC.resultsVC = self.resultsVC
            probegVC.mode = carData.mode
            self.navigationController?.pushViewController(probegVC, animated: true)
        }
    }
}


extension SerieModificationViewController {
    
    private func setUpUI () {
        view.backgroundColor = .white
        self.view.addSubview(tableView)
        self.view.addSubview(spinner)
        
        // [Car Select View]
        
        if (!isCarCreate) {
            self.view.addSubview(modelsScroll)
            self.view.addSubview(nextBtn)
            self.view.addSubview(submitBtn)
            
            nextBtn.addTarget(self, action: #selector(onNext(sender:)), for: .touchUpInside)
            submitBtn.addTarget(self, action: #selector(onSubmit(sender:)), for: .touchUpInside)
        }
        
        self.addConstraints()
    }
    
    private func addConstraints () {
        // [Car Select View]
        
        let viewsTop = !isCarCreate ? modelsScroll.snp.bottom : view.safeAreaLayoutGuide.snp.top
        let tableBottom = !isCarCreate ? submitBtn.snp.top : view.safeAreaLayoutGuide.snp.bottom
        
        if !isCarCreate {
            modelsScroll.snp.makeConstraints { (make) in
                make.top.equalTo(view.safeAreaLayoutGuide).offset(20)
                make.leading.trailing.equalToSuperview().inset(16)
                make.height.equalTo(48.0)
            }
            nextBtn.snp.makeConstraints { (make) in
                make.bottom.equalTo(submitBtn.snp.top).offset(-8)
                make.leading.trailing.equalToSuperview().inset(16)
                make.height.equalTo(44)
            }
            submitBtn.snp.makeConstraints { (make) in
                make.bottom.equalTo(view.safeAreaLayoutGuide).inset(20)
                make.leading.trailing.equalToSuperview().inset(16)
                make.height.equalTo(44)
            }
        }
        
        tableView.snp.makeConstraints { (make) in
            make.top.equalTo(viewsTop).offset(40)
            make.leading.trailing.equalToSuperview().inset(16)
            make.bottom.equalTo(tableBottom).offset(-12)
        }
        
        spinner.snp.makeConstraints { (make) in
            make.width.height.equalTo(50)
            make.center.equalToSuperview()
        }
    }
    
    private func setUpNavBar () {
        let backIcon = UIImage(named: "cancel")
        let backButton = UIBarButtonItem(image: backIcon, landscapeImagePhone: backIcon, style: .plain, target: self, action: #selector(goBack(sender:)))
        backButton.tintColor = .greyColor
        
        self.navigationItem.simpleNavBar(title: "Поколение", backButton: backButton)
        navigationItem.largeTitleDisplayMode = .always
        navigationController?.navigationBar.largeTitleTextAttributes = [
            NSAttributedString.Key.font: UIFont.systemFont(ofSize: 24, weight: .bold)
        ]
        navigationItem.title = vcType.rawValue
        navigationItem.hidesSearchBarWhenScrolling = false
        self.navigationController?.navigationItem.largeTitleDisplayMode = .always
        self.navigationController?.navigationBar.defaultNavBar()
    }

    // [Car Select View]
    
    private func handleSingleSelection () {
        nextBtn.isHidden = true
        submitBtn.isHidden = true
        tableView.separatorStyle = .singleLine
        self.addCloseIcon()
    }
    private func addCloseIcon () {
        let closeBarBnt = UIBarButtonItem(image: UIImage(named: "dismiss"), style: .plain, target: self, action: #selector(closeVC))
        closeBarBnt.tintColor = .greyColor
        self.navigationItem.rightBarButtonItem = closeBarBnt
    }
}



extension SerieModificationViewController {
    
    @objc private func updateModel (notification: NSNotification) {
        guard let userInfo = notification.userInfo else {
            return
        }
        
        if let model = userInfo["model"] as? Model, let index = userInfo["index"] as? Int {
            if (index != self.currentModelIndex) {
                if isCarCreate && lastSelectedRow != nil {
                    scrollModels[currentModelIndex]?[lastSelectedRow!].isSelected = false
                    lastSelectedRow = nil
                }
                self.currentModelIndex = index
                
                if scrollModels.count == 0 || scrollModels[index]?.count == 0 {
                    self.loadData(model: model, index: index)
                } else {
                    tableView.reloadData()
                }
            }
        }
    }
    
    private func loadData(model: Model, index: Int) {
        if (vcType == .serie) {
            self.loadSeries(model: model, index: index)
        } else if vcType == .modification {
            self.loadModifications(model: model, index: index)
        } else if vcType == .color {
            self.loadColors()
        }
    }
    
    private func handleError (_ error: RequestError) {
        switch error {
            case .general:
                self.showAlert("Упс...", "Неизвестная ошибка")
            case .parameter(let msg):
                self.showAlert("Упс...", msg)
        }
    }
    
    private func loadSeries (model: Model, index: Int) {
        let backendService = Backend()
        
        if (model.generation ?? []).count == 0 {
            tableView.tableHeaderView = emptyView
            tableView.reloadData()
        } else {
            tableView.tableHeaderView = nil
        }
        
        for (i, generation) in (model.generation ?? []).enumerated() {
            let parameters:[URLQueryItem] = [
                URLQueryItem(name: "model_id", value: "\(model.id)"),
                URLQueryItem(name: "generation_id", value: "\(generation.id)")
            ]
            let _request = Request(base: carData.saveToGarage ? .garage : .advert, parameters: parameters)
            let requestUrl = _request.getUrl(path: "cars/series")
            let request = URLRequest(url: requestUrl)
            self.isLoading = true
            
            backendService.fetchFromBackend(for: Response<[Serie]>.self, request: request, statusCode: 200) { (result) in
                self.isLoading = false
                switch result {
                    case .failure(let error):
                        self.handleError(error)
                    case .success(let _data):
                        self.models[index].generation![i].series = _data.results
                        self.fillScrollModels()
                }
            }
        }
    }
    
    private func loadModifications (model: Model, index: Int) {
        let backendService = Backend()
        
        if (model.generation ?? []).count == 0 {
            tableView.reloadData()
            tableView.tableHeaderView = emptyView
        } else {
            tableView.tableHeaderView = nil
        }
        
        for (i, generation) in (model.generation ?? []).enumerated() {
            if (generation.series ?? []).count == 0 {
                tableView.reloadData()
                tableView.tableHeaderView = emptyView
            } else {
                tableView.tableHeaderView = nil
            }
            for (s, serie) in (generation.series ?? []).enumerated() {
                let parameters:[URLQueryItem] = [
                    URLQueryItem(name: "serie_id", value: "\(serie.id)")
                ]
                let _request = Request(base: carData.saveToGarage ? .garage : .advert, parameters: parameters)
                let requestUrl = _request.getUrl(path: "cars/modifications")
                let request = URLRequest(url: requestUrl)
                self.isLoading = true
                
                backendService.fetchFromBackend(for: Response<[Modification]>.self, request: request, statusCode: 200) { (result) in
                    self.isLoading = false
                    switch result {
                        case .failure(let error):
                            self.handleError(error)
                        case .success(let _data):
                            self.models[index].generation?[i].series?[s].modifications = _data.results
                            self.fillModificationScrollModels()
                    }
                }
            }
        }
    }
    
    private func loadColors () {
        let backendService = Backend()
        let saveToGarage = carData.saveToGarage
        
        let request = URLRequest(url: Request(base: saveToGarage ? .garage : .advert).getUrl(path: saveToGarage ? "garage/colors/" : "cars/colors/"))
        self.isLoading = true
        
        backendService.fetchFromBackend(for: Response<[CarColor]>.self, request: request, statusCode: 200) { (result) in
            self.isLoading = false
            switch result {
                case .failure(let error):
                    self.handleError(error)
                case .success(let _data):
                    var podtyps: [PodtypViewModel] = []
                    for color in _data.results {
                        let podtyp = PodtypModel(id: color.id, ext: color.ext, name: color.name)
                        var podtModel = PodtypViewModel(model: podtyp)
                        podtModel.custom = UIColor.rgb(CGFloat(color.r_abbreviation ?? 0),
                                                       CGFloat(color.g_abbreviation ?? 0),
                                                       CGFloat(color.b_abbreviation ?? 0))
                        podtyps.append(podtModel)
                    }
                    self.scrollModels = [0 : podtyps]
                    self.tableView.reloadData()
            }
        }
    }
}
